package com.dosgi.module;

import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;

import com.dosgi.Dosgi;
import com.dosgi.IDosgiContext;
import com.dosgi.kit.StrKit;

public class ModuleContext implements IModuleContext {
	private Map<String, String> manifestAttributes;

	private String filePath;

	private ClassLoader classLoader;

	private String symbolicName;

	private String version;

	private IDosgiContext containerCtx;

	private IModule bootInstance;

	private Set<String> exportPackages = Collections.emptySet();;

	private Map<String, String> importPackages = Collections.emptyMap();

	private Map<String, String> requireModules = Collections.emptyMap();
	
	private Collection<IModuleContext> resolvedRequireModules = null;
	
	public ModuleContext(Map<String, String> manifestAttributes, String filePath) {
		this.containerCtx = Dosgi.context();
		this.manifestAttributes = manifestAttributes;
		this.filePath = filePath;
		this.symbolicName = manifestAttributes.get("Implementation-Title");
		this.version = manifestAttributes.get("Implementation-Version");
		initExportPackages();
		initImportPackages();
		initRequireModules();

		// 构造逻辑准备好后注册到框架容器上下文中
		containerCtx.registerModule(this);
	}

	private void initRequireModules() {
		String requireModuleStr = manifestAttributes.get("Require-Module");
		if (StrKit.isNotBlank(requireModuleStr)) {
			HashMap<String, String> _importModules = new HashMap<String, String>();
			String[] split = StrKit.split(requireModuleStr, ",");
			for (String str : split) {
				String[] nameVersion = getNameVersion(str);
				_importModules.put(nameVersion[0], nameVersion[1]);
			}
			requireModules = Collections.unmodifiableMap(_importModules);
		}
	}

	private String[] getNameVersion(String str) {
		String[] nameVersion = new String[2];
		if (str.indexOf(';') >= 0) {
			String[] split2 = StrKit.split(str, ";");
			nameVersion[0] = split2[0].trim();
			if (split2.length == 2)
				nameVersion[1] = split2[1].trim();

		} else
			nameVersion[0] = str.trim();
		return nameVersion;
	}

	private void initImportPackages() {
		String importPkg = manifestAttributes.get("Import-Package");
		if (StrKit.isNotBlank(importPkg)) {
			HashMap<String, String> _importPackages = new HashMap<String, String>();
			String[] split = StrKit.split(importPkg, ",");
			for (String str : split) {
				String[] nameVersion = getNameVersion(str);
				_importPackages.put(nameVersion[0], nameVersion[1]);
			}
			importPackages = Collections.unmodifiableMap(_importPackages);
		}
	}

	private void initExportPackages() {
		String exportPkg = manifestAttributes.get("Export-Package");
		if (StrKit.isNotBlank(exportPkg)) {
			HashSet<String> _exportPackages = new HashSet<String>();
			String[] split = StrKit.split(exportPkg, ",");
			for (String str : split) {
				_exportPackages.add(str.trim());
			}
			exportPackages = Collections.unmodifiableSet(_exportPackages);
		}
	}

	@Override
	public void setClassLoader(ClassLoader classLoader) {
		if (this.classLoader != null)
			throw new RuntimeException(
					"The ModuleContext classLoader had been set,can not been set again!");
		this.classLoader = classLoader;
	}

	public ClassLoader getClassLoader() {
		return classLoader;
	}

	@Override
	public void init() throws Exception {
		getInstance().init(this);
	}

	public void start() throws Exception {
		getInstance().start(this);
	}

	@Override
	public void stop() throws Exception {
		getInstance().stop(this);
		bootInstance = null;
	}

	public Map<String, String> getManifestAttributes() {
		return Collections.unmodifiableMap(manifestAttributes);
	}

	public String getSymbolicName() {
		return this.symbolicName;
	}

	public String getVersion() {
		return this.version;
	}

	public IDosgiContext getContainerCtx() {
		return containerCtx;
	}

	@Override
	public void registry(Class<?> clazz, Object bean) {
		containerCtx.beanFactory().registry(clazz, bean);
	}

	@Override
	public <T> T get(Class<T> clazz) {
		return containerCtx.beanFactory().get(clazz);
	}

	private IModule getInstance() throws Exception {
		if (bootInstance == null)
			synchronized (this) {
				if (bootInstance == null) {
					Class<?> mClass = getClassLoader().loadClass(
							manifestAttributes.get(BOOT_CLASS));
					if (IModule.class.isAssignableFrom(mClass))
						bootInstance = (IModule) mClass.newInstance();
					else
						throw new Exception(String.format("Module Boot-Class(%s) must implements IModule",
								mClass.getName()));
				}

			}
		return bootInstance;
	}

	public String getFilePath() {
		return filePath;
	}

	public Set<String> getExportPackages() {
		return exportPackages;
	}

	public Map<String, String> getImportPackages() {
		return importPackages;
	}

	public Map<String, String> getRequireModules() {
		return requireModules;
	}

	/**
	 * @return the 获取RequireModules声明的模块
	 */
	public final Collection<IModuleContext> getResolvedRequireModules() {
		if (resolvedRequireModules != null)
			return resolvedRequireModules;
		HashSet<IModuleContext> set = new HashSet<IModuleContext>();
		// 解析声明的依赖模块
		for (Entry<String, String> entry : requireModules.entrySet()) {
			String symbolicName = entry.getKey();
			String version = entry.getValue();
			IModuleContext mContext = containerCtx.getModule(symbolicName, version);
			if (mContext == null)
				continue;
			set.add(mContext);
		}
		resolvedRequireModules = Collections.unmodifiableSet(set);
		return resolvedRequireModules;
	}
	
	/**
	 * @return the 获取RequireModules声明和ImportPackages声明的模块
	 */
	public final Collection<IModuleContext> getResolvedRequireModulesWithImport() {
		Collection<IModuleContext> resolvedRequireModulesWithImport = getResolvedRequireModules();
		if (importPackages.isEmpty())
			return resolvedRequireModulesWithImport;
		resolvedRequireModulesWithImport = new HashSet<IModuleContext>(resolvedRequireModulesWithImport);
		// 解析导入包依赖的模块
		for (Entry<String, String> entry : importPackages.entrySet()) {
			String packageName = entry.getKey();
			String version = entry.getValue();
			IModuleContext mContext = containerCtx.getModuleByExportPackage(packageName, version);
			if (mContext == null)
				continue;
			resolvedRequireModulesWithImport.add(mContext);
		}
		return resolvedRequireModulesWithImport;
	}
}
